from typing import Tuple, List, Any

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.engine.base import Engine
from sqlalchemy.orm.session import Session
from sqlalchemy.orm.query import Query

import settings
from db.models import Base, Shipping
from scraper.utils import ShippingData
from utils import show_runtime


def get_engine_and_session_of_db() -> Tuple[Engine, Session]:
    """ Получаем объекты session и engine для работы с базой данных """

    record_connect_to_db = '{}+{}://{}:{}@{}/{}'.format(
         settings.DIALECT_DB,
         settings.DRIVER_DB,
         settings.POSTGRES_USER,
         settings.POSTGRES_PASSWORD,
         settings.POSTGRES_HOST,
         settings.POSTGRES_NAME
    )
    engine = create_engine(record_connect_to_db)
    Session = sessionmaker(bind=engine)
    session = Session()
    return (engine, session)


def close_engine_and_session_of_db(engine: Engine, session: Session) -> None:
    """ Завершаем работу с базой данных """

    session.close()
    engine.dispose()


def create_necessary_data_in_db(engine: Engine) -> None:
    """ Создаем необходимые данные в бд """

    Base.metadata.create_all(engine)


def filter_new_shipments(
    session: Session,
    list_of_shipments: List[ShippingData]
) -> List[ShippingData]:
    """ Отфильтровываем новые перевозки """

    list_of_new_shipments: List[ShippingData] = []
    _, session = get_engine_and_session_of_db()

    for shipping in list_of_shipments:
        query: Query = session.query(Shipping).filter_by(**shipping)
        is_shippings: bool = session.query(query.exists()).scalar()

        if not is_shippings:
            list_of_new_shipments.append(shipping)

    return list_of_new_shipments


def add_shipping(session: Session, shipping: ShippingData) -> None:
    """ Добавляем перевозку """

    new_shipping: Shipping = Shipping(**shipping)
    session.add(new_shipping)
    session.commit()


@show_runtime('Добавление новых перевозок')
def add_list_of_shipments(
    session: Session,
    list_of_shipments: List[ShippingData]
) -> None:
    """ Добавляем список перевозок """

    _ = [add_shipping(session, shipping) for shipping in list_of_shipments]
